home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / formats / iff / newiff.lzh / NewIFF / NewIFF.lzh / newiff / apps / Play8SVX / Play8SVX.c < prev   
C/C++ Source or Header  |  1992-05-18  |  24KB  |  823 lines

  1.  
  2. /** Play8SVX.c ************************************************************** 
  3.  * 
  4.  * Read and play sound sample from an IFF file.  21Jan85 
  5.  * 
  6.  * By Steve Hayes, Electronic Arts. 
  7.  * This software is in the public domain. 
  8.  * 
  9.  * Modified 05/91 for use with iffparse & to play notes - CAS_CBM
  10.  * requires linkage with several IFF modules - see Makefile
  11.  ****************************************************************************/ 
  12.  
  13. #include "iffp/8svxapp.h"
  14.  
  15. #include <exec/execbase.h>
  16. #include <graphics/gfxbase.h>
  17. #include <clib/alib_protos.h>
  18.  
  19. #ifdef LATTICE
  20. int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
  21. int chkabort(void) { return(0); }  /* really */
  22. #endif
  23.  
  24. /* prototypes for our functions */
  25. void cleanup(void);
  26. void bye(UBYTE *s,int error);
  27. void DUnpack(BYTE source[], LONG n, BYTE dest[]);
  28. BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x);
  29. LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename);
  30. void UnloadSample(struct EightSVXInfo *esvx);
  31. LONG LoadSBody(struct EightSVXInfo *esvx);
  32. void UnloadSBody(struct EightSVXInfo *esvx);
  33.  
  34. LONG ShowSample(struct EightSVXInfo *esvx);
  35.  
  36. LONG OpenAudio(void);
  37. void CloseAudio(void);
  38. LONG PlaySample(struct EightSVXInfo *esvx,
  39.         LONG octave, LONG note, UWORD volume, ULONG delay);
  40.  
  41. struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio *aio1,
  42.         BYTE *samptr, LONG ssize, ULONG period, UWORD volume);
  43.  
  44. #define MINARGS 2
  45. char *vers = "$VER: Play8SVX 37.9";
  46. char *Copyright = "Play8SVX v37.9 (Freely Redistributable)";
  47. char *usage = "Usage: Play8SVX 8SVXname";
  48.  
  49.  
  50. /* globals */
  51. struct Library *IFFParseBase   = NULL;
  52. struct Library *GfxBase = NULL;
  53.  
  54. BOOL   FromWb;
  55.  
  56. /* 8SVX Property chunks to be grabbed
  57.  */
  58. LONG    esvxprops[] = {
  59.         ID_8SVX, ID_VHDR,
  60.         ID_8SVX, ID_NAME,
  61.         ID_8SVX, ID_ATAK,
  62.         ID_8SVX, ID_RLSE,
  63.         ID_8SVX, ID_AUTH,
  64.         ID_8SVX, ID_Copyright,
  65.         TAG_DONE
  66.         };
  67.  
  68. /* 8SVX Collection chunks (more than one in file) to be gathered */
  69. LONG    esvxcollects[] = {
  70.         ID_8SVX, ID_ANNO,
  71.         TAG_DONE
  72.         };
  73.  
  74. /* 8SVX Chunk to stop on */
  75. LONG    esvxstops[] = {
  76.         ID_8SVX, ID_BODY,
  77.         TAG_DONE
  78.         };
  79.  
  80.  
  81. UBYTE nomem[]  = "Not enough memory\n";
  82. UBYTE noiffh[] = "Can't alloc iff\n";
  83.  
  84.  
  85.  
  86. /* For our allocated EightSVXInfo */
  87. struct EightSVXInfo  *esvx = NULL;
  88.  
  89.  
  90. /* 
  91.  * MAIN 
  92.  */
  93. void main(int argc, char **argv)
  94.    {
  95.    UBYTE *esvxname=NULL;
  96.    ULONG oct;
  97.    LONG error=0L;
  98.  
  99.    FromWb = argc ? FALSE : TRUE;
  100.  
  101.    if((argc<MINARGS)||(argv[argc-1][0]=='?'))
  102.     {
  103.     printf("%s\n%s\n",Copyright,usage);
  104.         bye("",RETURN_OK);
  105.     }
  106.  
  107.    esvxname = argv[1];
  108.  
  109. /* Open Libraries */
  110.    if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
  111.       bye("Can't open iffparse library.\n",RETURN_WARN);
  112.  
  113.  
  114. /* 
  115.  * Alloc one EightSVXInfo struct
  116.  */
  117.     if(!(esvx = (struct EightSVXInfo *)
  118.     AllocMem(sizeof(struct EightSVXInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
  119.         bye(nomem,RETURN_FAIL);
  120.  
  121. /*
  122.  * Here we set up our EightSVXInfo fields for our
  123.  * application.
  124.  * Above we have defined the propery and collection chunks
  125.  * we are interested in (some required like VHDR).
  126.  * We want to stop on BODY.
  127.  */
  128.     esvx->ParseInfo.propchks    = esvxprops;
  129.     esvx->ParseInfo.collectchks    = esvxcollects;
  130.     esvx->ParseInfo.stopchks    = esvxstops;
  131. /* 
  132.  * Alloc the IFF handle for the frame
  133.  */
  134.     if(!(esvx->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);
  135.  
  136.  
  137.     if(!(error = LoadSample(esvx, esvxname)))
  138.     {
  139.     ShowSample(esvx);
  140.  
  141.     if(!(error = OpenAudio()))
  142.         {
  143.         /* If we think this is a sound effect, play it as such (note=-1) */
  144.         if((esvx->Vhdr.ctOctave==1)&&(esvx->Vhdr.samplesPerSec)
  145.         &&(esvx->Vhdr.oneShotHiSamples)&&(!esvx->Vhdr.repeatHiSamples))
  146.         {
  147.         PlaySample(esvx,0,-1,64,0);
  148.         }
  149.         /* Else play it like an instrument */
  150.         else
  151.         {
  152.             for(oct=0; oct < esvx->Vhdr.ctOctave; oct++)
  153.             {
  154.                 PlaySample(esvx,oct,0,64,50);
  155.                 PlaySample(esvx,oct,4,64,50);
  156.                 PlaySample(esvx,oct,7,64,50);
  157.             }
  158.         }
  159.         CloseAudio();
  160.         }
  161.         else printf("error opening audio device\n");
  162.     }
  163.     else
  164.         printf("%s\n",IFFerr(error));
  165.  
  166.     cleanup();
  167.     exit(RETURN_OK);
  168.     }
  169.  
  170.  
  171. void bye(UBYTE *s,int error)
  172.    {
  173.    if((*s)&&(!FromWb)) printf("%s\n",s);
  174.    cleanup();
  175.    exit(error);
  176.    }
  177.  
  178.  
  179. void cleanup()
  180.    {
  181.    if(esvx)        
  182.     {
  183.     DD(bug("About to UnloadSample\n"));
  184.     UnloadSample(esvx);
  185.  
  186.     DD(bug("About to FreeIFF\n"));
  187.     if(esvx->ParseInfo.iff)     FreeIFF(esvx->ParseInfo.iff);
  188.  
  189.     DD(bug("About to free EightSVXInfo\n"));
  190.         FreeMem(esvx,sizeof(struct EightSVXInfo));
  191.     }
  192.  
  193.    if(IFFParseBase)      CloseLibrary(IFFParseBase);
  194.    }
  195.  
  196.  
  197. /** ShowSample() **********************************************
  198.  * 
  199.  * Show sample information after calling LoadSample()
  200.  * 
  201.  *************************************************************************/
  202. LONG ShowSample(struct EightSVXInfo *esvx)
  203.     {
  204.     LONG error = 0L;
  205.     BYTE *buf;
  206.     Voice8Header *vhdr;
  207.  
  208.     if(!esvx)            return(CLIENT_ERROR);
  209.     if(!(buf = esvx->sample))    return(CLIENT_ERROR);
  210.  
  211.     /* LoadSample copied VHDR and NAME (if any) to our esvx frame */
  212.     vhdr = &esvx->Vhdr;
  213.     if(esvx->name[0]) printf("\nNAME: %s",esvx->name);
  214.  
  215.     printf("\n\nVHDR Info:");
  216.     printf("\noneShotHiSamples=%ld", vhdr->oneShotHiSamples); 
  217.     printf("\nrepeatHiSamples=%ld", vhdr->repeatHiSamples); 
  218.     printf("\nsamplesPerHiCycle=%ld", vhdr->samplesPerHiCycle); 
  219.     printf("\nsamplesPerSec=%ld", vhdr->samplesPerSec); 
  220.     printf("\nctOctave=%ld", vhdr->ctOctave); 
  221.     printf("\nsCompression=%ld", vhdr->sCompression); 
  222.     printf("\nvolume=0x%lx", vhdr->volume); 
  223.     printf("\nData = %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld",  
  224.            buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); 
  225.     printf("\n       %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld ...\n",  
  226.            buf[8+0],buf[8+1],buf[8+2],buf[8+3],buf[8+4],buf[8+5],
  227.            buf[8+6],buf[8+ 7]); 
  228.  
  229.     return(error);
  230.     } 
  231.  
  232.  
  233. /* OpenAudio
  234.  *
  235.  * Opens audio device for one audio channel, 2 IO requests
  236.  * Returns 0 for success
  237.  *
  238.  * Based on code by Dan Baker
  239.  */
  240.  
  241. UBYTE           whichannel[] = { 1,2,4,8 };
  242.  
  243. /* periods for scale starting at   65.40Hz (C) with 128 samples per cycle
  244.  *                            or  130.81Hz (C) with  64 samples per cycle
  245.  *                            or  261.63Hz (C) with  32 samples per cycle
  246.  *                            or  523.25Hz (C) with  16 samples per cycle
  247.  *                            or 1046.50Hz (C) with   8 samples per cycle
  248.  *                            or 2093.00Hz (C) with   4 samples per cycle
  249.  */
  250.  
  251. UWORD   per_ntsc[12]= { 428, 404, 380, 360,
  252.             340, 320, 302, 286,
  253.             270, 254, 240, 226 };
  254.  
  255. /* periods adjusted for system clock frequency */
  256. UWORD   per[12];
  257.  
  258. /* Note - these values 3579545 NTSC, 3546895 PAL */
  259. #define NTSC_CLOCK 3579545L
  260. #define PAL_CLOCK  3546895L
  261.  
  262. #define AIOCNT 4
  263. struct     IOAudio *aio[AIOCNT] = {NULL};       /* Ptrs to IO blocks for commands  */
  264.  
  265. struct     MsgPort *port;       /* Pointer to a port so the device can reply */
  266. BOOL    devopened;
  267. ULONG    clock = NTSC_CLOCK;     /* Will check for PAL and change if necessary */
  268.  
  269.  
  270. LONG OpenAudio()
  271. {
  272. extern    struct ExecBase *SysBase;
  273. LONG     error=0L;
  274. ULONG   period;
  275. int    k;
  276.  
  277. if(devopened)    return(-1);
  278.  
  279. /*-------------------------------------------------------------------------*/
  280. /* Ask the system if we are PAL or NTSC and set clock constant accordingly */
  281. /*-------------------------------------------------------------------------*/
  282. if(GfxBase=OpenLibrary("graphics.library",0L))
  283.     {
  284.     if(((struct GfxBase *)GfxBase)->DisplayFlags & PAL)
  285.         clock = PAL_CLOCK;
  286.     else
  287.         clock = NTSC_CLOCK;
  288.     CloseLibrary((struct Library *) GfxBase);
  289.     }
  290.  
  291. printf("OpenAudio: For period calculations, clock=%ld\n", clock);
  292.  
  293. /* calculate period values for one octave based on system clock */
  294. for(k=0; k<12; k++)
  295.     {
  296.     period = ((per_ntsc[k] * clock) + (NTSC_CLOCK >> 1)) / NTSC_CLOCK;
  297.     per[k] = period;
  298.     D(bug("per[%ld]=%ld ",k,per[k]));
  299.     }
  300. D(bug("\n"));
  301.  
  302. /*-------------------------------------------------------------------*/
  303. /* Create a reply port so the audio device can reply to our commands */
  304. /*-------------------------------------------------------------------*/
  305. if(!(port=CreatePort(0,0)))
  306.     { error = 1; goto bailout; }
  307.  
  308. /*--------------------------------------------------------------------------*/
  309. /*  Create audio I/O blocks so we can send commands to the audio device     */
  310. /*--------------------------------------------------------------------------*/
  311. for(k=0; k<AIOCNT; k++)
  312.     {
  313.     if(!(aio[k]=(struct IOAudio *)CreateExtIO(port,sizeof(struct IOAudio))))
  314.     { error = k+2; goto bailout; }
  315.     }
  316.  
  317. /*----------------------------------------------------------------------*/
  318. /* Set up the audio I/O block for channel allocation:                   */
  319. /* ioa_Request.io_Message.mn_ReplyPort is the address of a reply port.  */
  320. /* ioa_Request.io_Message.mn_Node.ln_Pri sets the precedence (priority) */
  321. /*   of our use of the audio device. Any tasks asking to use the audio  */
  322. /*   device that have a higher precedence will steal the channel from us.*/
  323. /* ioa_Request.io_Command is the command field for IO.                  */
  324. /* ioa_Request.io_Flags is used for the IO flags.                       */
  325. /* ioa_AllocKey will be filled in by the audio device if the allocation */
  326. /*   succeeds. We must use the key it gives for all other commands sent.*/
  327. /* ioa_Data is a pointer to the array listing the channels we want.     */
  328. /* ioa_Length tells how long our list of channels is.                   */
  329. /*----------------------------------------------------------------------*/
  330. aio[0]->ioa_Request.io_Command               = ADCMD_ALLOCATE;
  331. aio[0]->ioa_Request.io_Flags                 = ADIOF_NOWAIT;
  332. aio[0]->ioa_AllocKey                         = 0;
  333. aio[0]->ioa_Data                             = whichannel;
  334. aio[0]->ioa_Length                           = sizeof(whichannel);
  335.  
  336. /*-----------------------------------------------*/
  337. /* Open the audio device and allocate a channel  */
  338. /*-----------------------------------------------*/
  339. if(!(OpenDevice("audio.device",0L, (struct IORequest *) aio[0] ,0L)))
  340.     devopened = TRUE;
  341. else { error = 5; goto bailout; }
  342.  
  343. /* Clone the flags, channel allocation, etc. into other IOAudio requests */
  344. for(k=1; k<AIOCNT; k++)    *aio[k] = *aio[0];
  345.  
  346. bailout:
  347. if(error)    
  348.     {
  349.     printf("OpenAudio errored out at step %ld\n",error);
  350.     CloseAudio();
  351.     }
  352. return(error);
  353. }
  354.  
  355.  
  356. /* CloseAudio
  357.  *
  358.  * Close audio device as opened by OpenAudio, null out pointers
  359.  */
  360. void CloseAudio()
  361. {
  362. int k;
  363.  
  364. D(bug("Closing audio device...\n"));
  365.  
  366. /* Note - we know we have no outstanding audio requests */
  367. if(devopened)
  368.     {
  369.     CloseDevice((struct IORequest *) aio[0]);
  370.     devopened = FALSE;
  371.     }
  372.  
  373. for(k=0; k<AIOCNT; k++)
  374.     {
  375.     if(aio[k])     DeleteExtIO(aio[k]), aio[k] = NULL;
  376.     }
  377.  
  378. if(port)       DeletePort(port),  port = NULL;
  379. }
  380.  
  381.  
  382. /** PlaySample() **********************************************
  383.  * 
  384.  * Play a note in octave for delay/50ths of a second 
  385.  * OR Play a sound effect (set octave and note to 0, -1)
  386.  *
  387.  * Requires successful OpenAudio() called previously
  388.  *
  389.  * When playing notes:
  390.  * Expects note values between 0 (C) and 11 (B#)
  391.  * Uses largest octave sample in 8SVX as octave 0, next smallest
  392.  *   as octave 1, etc.
  393.  *
  394.  * Notes - this simple example routine does not do ATAK and RLSE)
  395.  *       - use of Delay for timing is simplistic, synchronous, and does
  396.  *        not take into account that the oneshot itself may be
  397.  *        longer than the delay.
  398.  *         Use timer.device for more accurate asynchronous delays
  399.  *
  400.  *************************************************************************/
  401. /* Max playable sample in one IO request is 128K */
  402. #define MAXSAMPLE 131072
  403.  
  404. LONG    PlaySample(struct EightSVXInfo *esvx,
  405.             LONG octave, LONG note, UWORD volume, ULONG delay)
  406. {
  407. /* pointers to outstanding requests */
  408. struct        IOAudio    *aout0=NULL, *aout1=NULL;    
  409. ULONG        period;
  410. LONG        osize, rsize;
  411. BYTE        *oneshot, *repeat;
  412.  
  413. if(!devopened)    return(-1);
  414.  
  415. if(note > 11) note=0;
  416.  
  417. if( note == -1 ) period = clock / esvx->Vhdr.samplesPerSec;
  418. else          period = per[note]; /* table set up by OpenAudio */
  419.  
  420. if(octave > esvx->Vhdr.ctOctave) octave = 0;
  421. if(volume > 64)    volume = 64;
  422.  
  423. oneshot = esvx->osamps[octave];
  424. osize   = esvx->osizes[octave];
  425. repeat  = esvx->rsamps[octave];
  426. rsize   = esvx->rsizes[octave];
  427.  
  428. D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
  429.     oneshot, osize, repeat, rsize));
  430.  
  431. /*------------------------------------------------------------*/
  432. /* Set up audio I/O blocks to play a sample using CMD_WRITE.  */
  433. /* Set up one request for the oneshot and one for repeat      */
  434. /* (all ready for simple case, but we may not need both)      */
  435. /* The io_Flags are set to ADIOF_PERVOL so we can set the     */
  436. /*    period (speed) and volume with the our sample;          */
  437. /* ioa_Data points to the sample; ioa_Length gives the length */
  438. /* ioa_Cycles tells how many times to repeat the sample       */
  439. /* If you want to play the sample at a given sampling rate,   */
  440. /* set ioa_Period = clock/(given sampling rate)               */
  441. /*------------------------------------------------------------*/
  442. aio[0]->ioa_Request.io_Command             =CMD_WRITE;
  443. aio[0]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  444. aio[0]->ioa_Data                           =oneshot;
  445. aio[0]->ioa_Length                         =osize;
  446. aio[0]->ioa_Period                         =period;
  447. aio[0]->ioa_Volume                         =volume;
  448. aio[0]->ioa_Cycles                         =1;
  449.  
  450. aio[2]->ioa_Request.io_Command             =CMD_WRITE;
  451. aio[2]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  452. aio[2]->ioa_Data                           =repeat;
  453. aio[2]->ioa_Length                         =rsize;
  454. aio[2]->ioa_Period                         =period;
  455. aio[2]->ioa_Volume                         =volume;
  456. aio[2]->ioa_Cycles                         =0;    /* repeat until stopped */
  457.  
  458. /*---------------------------------------------------*/
  459. /* Send the command to start a sound using BeginIO() */
  460. /* Go to sleep and wait for the sound to finish with */
  461. /* WaitIO() to wait and get the get the ReplyMsg     */
  462. /*---------------------------------------------------*/
  463. printf("Starting tone O len %ld for %0ld cyc, R len %ld for %0ld cyc, per=%ld...",
  464.         osize, aio[0]->ioa_Cycles, rsize, aio[1]->ioa_Cycles, period);
  465.  
  466. if(osize)
  467.     {
  468.     /* Simple case for oneshot sample <= 128K (ie. most samples) */
  469.     if(osize <= MAXSAMPLE)    BeginIO((struct IORequest *)(aout0=aio[0]));
  470.  
  471.     /* Note - this else case code is for samples >128K */
  472.     else
  473.     {
  474.     *aio[1] = *aio[0];
  475.     aout0 = playbigsample(aio[0],aio[1],oneshot,osize,period,volume);
  476.     }
  477.      }
  478.  
  479. if(rsize)
  480.     {
  481.     /* Simple case for repeat sample <= 128K (ie. most samples) */
  482.     if(rsize <= MAXSAMPLE)    BeginIO((struct IORequest *)(aout1=aio[2]));
  483.  
  484.     /* Note - this else case code is for samples >128K */
  485.     else
  486.     {
  487.     *aio[3] = *aio[2];
  488.     aout1 = playbigsample(aio[2],aio[3],repeat,rsize,period,volume);
  489.     }
  490.      }
  491.  
  492. if(delay)    Delay(delay);    /* crude timing for notes */
  493.  
  494. /* Wait for any requests we still have out */
  495. if(aout0) WaitIO(aout0);
  496.  
  497. if(aout1)
  498.    {
  499.    if(note >= 0) AbortIO(aout1);    /* if a note, stop it now */
  500.    WaitIO(aout1);
  501.    }
  502.  
  503. printf("Done\n");
  504. }
  505.  
  506.  
  507. /** playbigsample() ********************************************************
  508.  * 
  509.  *  called by playsample to deal with samples > 128K
  510.  *
  511.  *  wants pointers to two ready-to-use IOAudio iorequest blocks
  512.  *
  513.  *  returns pointer to the IOAudio request that is still out
  514.  *   or NULL if none (error)
  515.  *************************************************************************/
  516.  
  517. struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio* aio1,
  518.             BYTE *samptr, LONG ssize, ULONG period, UWORD volume)
  519. {
  520. struct IOAudio *aio[2];
  521. LONG   size;
  522. int    req=0, reqn=1;    /* current and next IOAudio request indexes */
  523.  
  524. if((!aio0)||(!aio1)||(ssize < MAXSAMPLE))    return(NULL);
  525.  
  526. aio[req]  = aio0;
  527. aio[reqn] = aio1;
  528.  
  529. /* start the first 128 K playing */
  530. aio[req]->ioa_Request.io_Command             =CMD_WRITE;
  531. aio[req]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  532. aio[req]->ioa_Data                           =samptr;
  533. aio[req]->ioa_Length                 =MAXSAMPLE;
  534. aio[req]->ioa_Period                         =period;
  535. aio[req]->ioa_Volume                         =volume;
  536. aio[req]->ioa_Cycles                         =1;
  537. BeginIO((struct IORequest*)aio[req]);
  538.  
  539. for(samptr=samptr + MAXSAMPLE, size = ssize - MAXSAMPLE;
  540.     size > 0;
  541.         samptr += MAXSAMPLE)
  542.     {
  543.     /* queue the next piece of sample */
  544.     reqn = req ^ 1;    /* alternate IO blocks 0 and 1 */
  545.     aio[reqn]->ioa_Request.io_Command             =CMD_WRITE;
  546.     aio[reqn]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  547.     aio[reqn]->ioa_Data                           =samptr;
  548.     aio[reqn]->ioa_Length = (size > MAXSAMPLE) ? MAXSAMPLE : size;
  549.     aio[reqn]->ioa_Period                         =period;
  550.     aio[reqn]->ioa_Volume                         =volume;
  551.     aio[reqn]->ioa_Cycles                         =1;
  552.     BeginIO((struct IORequest*)aio[reqn]);
  553.  
  554.     /* Wait for previous request to finish */
  555.     WaitIO(aio[req]);
  556.     /* decrement size */
  557.     size = (size > MAXSAMPLE) ? size-MAXSAMPLE : 0;
  558.     req = reqn;        /* switch between aio[0] and aio[1] */
  559.     }
  560. return(aio[reqn]);
  561. }
  562.  
  563. /** LoadSample() **********************************************************
  564.  * 
  565.  * Read 8SVX, given an initialized EightSVXInfo with not-in-use IFFHandle,
  566.  *   and filename.  Leaves the IFFHandle open so you can FindProp()
  567.  *   additional chunks or copychunks().  You must UnloadSample()
  568.  *   when done.  UnloadSample will closeifile if the file is still
  569.  *   open.
  570.  *
  571.  * Fills in esvx->Vhdr and Name, and allocates/loads esvx->sample,
  572.  *   setting esvx->samplebytes to size for deallocation.
  573.  *
  574.  * Returns 0 for success of an IFFERR (libraries/iffparse.h)
  575.  *************************************************************************/
  576. LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename)
  577.     {
  578.     struct IFFHandle *iff;
  579.     struct StoredProperty *sp;
  580.     Voice8Header *vhdr;
  581.     BYTE *oneshot, *repeat;
  582.     ULONG osize, rsize, spcyc;
  583.     int oct;
  584.     LONG error = 0L;
  585.  
  586.     D(bug("LoadSample:\n"));
  587.     
  588.     if(!esvx)                return(CLIENT_ERROR);
  589.     if(!(iff=esvx->ParseInfo.iff))    return(CLIENT_ERROR);
  590.  
  591.     if(!(error = openifile((struct ParseInfo *)esvx, filename, IFFF_READ)))
  592.     {
  593.     printf("Reading '%s'...\n",filename);
  594.     error = parseifile((struct ParseInfo *)esvx,
  595.             ID_FORM, ID_8SVX,
  596.             esvx->ParseInfo.propchks,
  597.             esvx->ParseInfo.collectchks,
  598.             esvx->ParseInfo.stopchks);
  599.  
  600.     D(bug("LoadSample: after parseifile - error = %ld\n",error));
  601.  
  602.     if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
  603.         {
  604.         if(contextis(iff,ID_8SVX,ID_FORM))
  605.         {
  606.         D(bug("LoadSample: context is 8SVX\n"));
  607.         if(!(sp = FindProp(iff,ID_8SVX,ID_VHDR)))
  608.             {
  609.             message("No 8SVX.VHDR!");
  610.             error = IFFERR_SYNTAX;
  611.             }
  612.         else
  613.             {
  614.             D(bug("LoadSample: Have VHDR\n"));
  615.             /* copy Voice8Header into frame */
  616.             vhdr = (Voice8Header *)(sp->sp_Data);
  617.             *(&esvx->Vhdr) = *vhdr;
  618.             /* copy name if any */
  619.             esvx->name[0]='\0';
  620.             if(sp = FindProp(iff,ID_8SVX,ID_NAME))
  621.             {
  622.             strncpy(esvx->name,sp->sp_Data,sp->sp_Size);
  623.             esvx->name[MIN(sp->sp_Size,79)] = '\0';
  624.             }
  625.                 error = LoadSBody(esvx);
  626.             D(bug("LoadSample: After LoadSBody - error = %ld\n",error));
  627.             if(!error)
  628.             {
  629.             osize   = esvx->Vhdr.oneShotHiSamples;
  630.             rsize   = esvx->Vhdr.repeatHiSamples;
  631.             spcyc    = esvx->Vhdr.samplesPerHiCycle;
  632.             if(!spcyc) spcyc = esvx->Vhdr.repeatHiSamples;
  633.             if(!spcyc) spcyc = 8;
  634.  
  635.             oneshot = esvx->sample;
  636.  
  637.             for(oct = esvx->Vhdr.ctOctave-1; oct >= 0;
  638.                  oct--, oneshot+=(osize+rsize),
  639.                     osize <<= 1, rsize <<=1, spcyc <<=1)
  640.                     {
  641.                     repeat  = oneshot + osize;
  642.                 esvx->osizes[oct] = osize;
  643.                 if(osize) esvx->osamps[oct] = oneshot;
  644.                 else      esvx->osamps[oct] = 0;
  645.                 esvx->rsizes[oct] = rsize;
  646.                 if(rsize) esvx->rsamps[oct] = repeat;
  647.                 else      esvx->rsamps[oct] = 0;
  648.                 esvx->spcycs[oct] = spcyc;
  649.  
  650.              D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
  651.                 oneshot, osize, repeat, rsize));
  652.  
  653.                 }
  654.                 }
  655.             }
  656.         }
  657.         else
  658.         {
  659.         message("Not an 8SVX\n");
  660.         error = NOFILE;
  661.         }
  662.         }
  663.     }
  664.  
  665.     if(error)
  666.     {
  667.     closeifile((struct ParseInfo *)esvx);
  668.     UnloadSample(esvx);
  669.     }
  670.     return(error);
  671.     }
  672.  
  673.  
  674. /** UnloadSample() *******************************************************
  675.  * 
  676.  * Frees and closes everything opened/alloc'd by LoadSample()
  677.  *
  678.  *************************************************************************/
  679. void UnloadSample(struct EightSVXInfo *esvx)
  680.     {
  681.     if(esvx)
  682.     {
  683.     UnloadSBody(esvx);
  684.     closeifile((struct ParseInfo *)esvx);
  685.     }
  686.     }
  687.  
  688.  
  689. /** LoadSBody() ***********************************************************
  690.  * 
  691.  * Read a 8SVX Sample BODY into RAM.  
  692.  * 
  693.  *************************************************************************/
  694. LONG LoadSBody(struct EightSVXInfo *esvx)
  695.     {
  696.     struct IFFHandle *iff;
  697.     LONG sbytes, rlen, error = 0L; 
  698.     ULONG memtype;
  699.     Voice8Header *vhdr = &esvx->Vhdr;
  700.     BYTE *t;
  701.  
  702.     D(bug("LoadSBody:\n"));
  703.  
  704.     if(!(iff=esvx->ParseInfo.iff))    return(CLIENT_ERROR);
  705.     if(!esvx)                return(CLIENT_ERROR);
  706.  
  707.     if(!(currentchunkis(iff,ID_8SVX,ID_BODY)))
  708.     {
  709.     message("LoadSBody: not at BODY!");
  710.     return(IFFERR_READ);
  711.     }
  712.  
  713.     sbytes  = ChunkMoreBytes(CurrentChunk(iff)); 
  714.  
  715.     /* if we have to decompress, let's just load it into public mem */
  716.     memtype = vhdr->sCompression ? MEMF_PUBLIC : MEMF_CHIP;
  717.  
  718.     D(bug("LoadSBody: samplebytes=%ld, compression=%ld\n",
  719.             sbytes,vhdr->sCompression));
  720.     
  721.     if(!(esvx->sample = (BYTE *)AllocMem(sbytes, memtype))) 
  722.     {
  723.         error = CLIENT_ERROR; 
  724.     }
  725.     else 
  726.     {
  727.     D(bug("LoadSBody: have load buffer\n"));
  728.     esvx->samplebytes = sbytes; 
  729.         if(rlen=ReadChunkBytes(iff,esvx->sample,sbytes) != sbytes)
  730.         error = IFFERR_READ;
  731.  
  732.     if(error)
  733.         {
  734.         D(bug("LoadSBody: ReadChunkBytes error = %ld, read %ld bytes\n",
  735.             error));
  736.         UnloadSample(esvx);
  737.         }
  738.     else if (vhdr->sCompression) /* Decompress, if needed. */
  739.         { 
  740.             if(t = (BYTE *)AllocMem(sbytes<<1, MEMF_CHIP)) 
  741.         {
  742.         D(bug("LoadSBody: have decompression buffer\n"));
  743.                 DUnpack(esvx->sample, sbytes, t); 
  744.                 FreeMem(esvx->sample, sbytes); 
  745.                 esvx->sample = t;
  746.                 esvx->samplebytes = sbytes << 1;
  747.         }
  748.         else
  749.         {
  750.         UnloadSample(esvx);
  751.         error = IFFERR_NOMEM;
  752.         }
  753.         } 
  754.     }
  755.     return(error);
  756.     } 
  757.  
  758.  
  759. /** UnloadSBody() ********************************************************
  760.  * 
  761.  * Deallocates esvx->smaple  
  762.  * 
  763.  *************************************************************************/
  764. void UnloadSBody(struct EightSVXInfo *esvx)
  765.     {
  766.     if(esvx)
  767.     {
  768.     if(esvx->sample)
  769.         {
  770.         DD(bug("About to free SBody\n"));
  771.         FreeMem(esvx->sample,esvx->samplebytes);
  772.         esvx->sample = NULL;
  773.         }
  774.     esvx->samplebytes = NULL;
  775.     }
  776.     }
  777.  
  778.  
  779. /* DUnpack.c --- Fibonacci Delta decompression by Steve Hayes */
  780.  
  781. /* Fibonacci delta encoding for sound data */
  782. BYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
  783.  
  784. /* Unpack Fibonacci-delta encoded data from n byte source
  785.  * buffer into 2*n byte dest buffer, given initial data
  786.  * value x.  It returns the lats data value x so you can
  787.  * call it several times to incrementally decompress the data.
  788.  */
  789.  
  790. BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x)
  791.    {
  792.    BYTE d;
  793.    LONG i, lim;
  794.  
  795.    lim = n << 1;
  796.    for (i=0; i < lim; ++i)
  797.       {
  798.       /* Decode a data nibble, high nibble then low nibble */
  799.       d = source[i >> 1];    /* get a pair of nibbles */
  800.       if (i & 1)             /* select low or high nibble */
  801.          d &= 0xf;           /* mask to get the low nibble */
  802.       else
  803.          d >>= 4;            /* shift to get the high nibble */
  804.       x += codeToDelta[d];   /* add in the decoded delta */
  805.       dest[i] = x;           /* store a 1 byte sample */
  806.       }
  807.    return(x);
  808.    }
  809.  
  810. /* Unpack Fibonacci-delta encoded data from n byte
  811.  * source buffer into 2*(n-2) byte dest buffer.
  812.  * Source buffer has a pad byte, an 8-bit initial
  813.  * value, followed by n-2 bytes comprising 2*(n-2)
  814.  * 4-bit encoded samples.
  815.  */
  816.  
  817. void DUnpack(source, n, dest)
  818. BYTE source[], dest[];
  819. LONG n;
  820.    {
  821.    D1Unpack(source+2, n-2, dest, source[1]);
  822.    }
  823.